package gui.batches;

import core.ContainerType;
import core.CoreFacade;
import core.Item;
import core.ItemBarcode;
import core.Product;
import core.ProductContainer;
import gui.common.*;
import gui.item.ItemData;
import gui.product.*;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.swing.Timer;

/**
 * Controller class for the remove item batch view.
 */
public class RemoveItemBatchController extends Controller implements
		IRemoveItemBatchController {
    
    private boolean scannerEnabled;
    private CoreFacade model;
    
    private List<Product> productsEffected;
    private Map<Product, ArrayList<ItemData>> removedItems;    
    private Timer scannerTimer = new Timer(500,
			
			new ActionListener()
			{
				@Override
				public void actionPerformed(ActionEvent arg0) 
				{
                                    removeItem();
				}
		
			}
			
			);
	
	
	/**
	 * Constructor.
	 * 
	 * @param view Reference to the remove item batch view.
	 */
	public RemoveItemBatchController(IView view) {
		super(view);
                
                scannerEnabled = false;
                model = CoreFacade.getInstance();
                model.clearHistory();
                productsEffected = new ArrayList<Product>();
                removedItems = new HashMap<Product, ArrayList<ItemData>>();

		construct();
                
	}
	
	/**
	 * Returns a reference to the view for this controller.
	 */
	@Override
	protected IRemoveItemBatchView getView() {
		return (IRemoveItemBatchView)super.getView();
	}

	/**
	 * Loads data into the controller's view.
	 * 
	 *  {@pre None}
	 *  
	 *  {@post The controller has loaded data into its view}
	 */
	@Override
	protected void loadValues() 
    {
            /*if(productsEffected.isEmpty()) 
                return;*/
		Product selected = null;
		ProductData newSelected = null;
		
		if(getView().getSelectedProduct() != null)
		{
			selected = (Product)getView().getSelectedProduct().getTag();
		}
		
        ProductData[] productDataToBeRemoved = new ProductData[productsEffected.size()];
        
        for(int i = 0; i < productsEffected.size(); i++)
        {
            ProductData pd = convertToProductData(productsEffected.get(i), 
            						removedItems.get(productsEffected.get(i)).size());
            productDataToBeRemoved[i] = pd;
            
            if((selected != null) &&
               (productsEffected.get(i).getDescription().compareTo(selected.getDescription()) == 0))
            {
            	newSelected = productDataToBeRemoved[i];
            }
        }
        
        
        getView().setProducts(productDataToBeRemoved);
        
        getView().selectProduct(newSelected);
        
        //getView().giveBarcodeFocus();
	}
	
	private void reloadItems()
	{
		
		if (getView().getSelectedProduct() == null)
		{
			ItemData[] empty = new ItemData[0];
			getView().setItems(empty);
			return;
		}
		
		Item selectedItem = null;
		ItemData newSelect = null;
		
		if (getView().getSelectedItem() != null)
		{
			selectedItem = (Item)getView().getSelectedItem().getTag();
		}
		
		Product p = model.getProduct(getView().getSelectedProduct().getBarcode());
				
		ArrayList<ItemData> theItems = removedItems.get(p);
		
		
		
		if (theItems == null) 
		{
			return;
		}
		
		if (theItems.size() == 0) 
		{
			return;
		}
		
		ItemData[] addedItemsData = new ItemData[theItems.size()];
		
		for (int i = 0; i < theItems.size(); i++)
		{
			addedItemsData[i] = theItems.get(i);
			
			if ((selectedItem != null) && 
				(selectedItem.getBarcode().equals(theItems.get(i).getBarcode()) == true))
			{
				newSelect = addedItemsData[i];
			}
		}
		
		getView().setItems(addedItemsData);
		
		getView().selectItem(newSelect);
		
	}	

	/**
	 * Sets the enable/disable state of all components in the controller's view.
	 * A component should be enabled only if the user is currently
	 * allowed to interact with that component.
	 * 
	 * {@pre None}
	 * 
	 * {@post The enable/disable state of all components in the controller's view
	 * have been set appropriately.}
	 */
	@Override
	protected void enableComponents() {
            enableUndoRedo();
            getView().enableItemAction(false);
            
            getView().setUseScanner(true);
            scannerEnabled = true;
	}
	private void enableUndoRedo()
	{
		getView().enableUndo(model.canUndo());
        getView().enableRedo(model.canRedo());
	}

	/**
	 * This method is called when any of the fields in the
	 * add item batch view have been changed by the user.
	 */
	@Override
	public void valuesChanged()
	{
		
	}
	
	/**
	 * This method is called when the "Item Barcode" field is changed
	 * in the remove item batch view by the user.
	 */
	@Override
	public void barcodeChanged() 
        {
            getView().enableItemAction(false);
            
            if(getView().getUseScanner())
            {
                if (scannerTimer.isRunning())
                {
                        scannerTimer.restart();
                }
                else if (!scannerTimer.isRunning())
                {
                        scannerTimer.start();
                }
                if(getView().getBarcode().isEmpty())
                {
                	scannerTimer.stop();
                }
            }
            else
            {
                String input = getView().getBarcode();
                if(input.isEmpty())
                {
                    getView().enableItemAction(false);
                }
                else
                {
                    getView().enableItemAction(true);
                }
            }
            
            
	}
	
	/**
	 * This method is called when the "Use Barcode Scanner" setting is changed
	 * in the remove item batch view by the user.
	 */
	@Override
	public void useScannerChanged() 
        {
            if (getView().getUseScanner() != scannerEnabled)
		{
			getView().setBarcode("");
			getView().enableItemAction(false);
			scannerEnabled = getView().getUseScanner();
		}
            
	}
	
	/**
	 * This method is called when the selected product changes
	 * in the remove item batch view.
	 */
	@Override
	public void selectedProductChanged() 
        {
            String bCode = getView().getSelectedProduct().getBarcode();
            Product product = model.getProduct(bCode);
            
            ArrayList<ItemData> items = removedItems.get(product);
            
            ItemData[] itemDataToBeRemoved = new ItemData[items.size()];
            
            for(int i = 0; i < itemDataToBeRemoved.length; i++)
            {
                itemDataToBeRemoved[i] = items.get(i);
            }
            
            getView().setItems(itemDataToBeRemoved);
	}
	
	/**
	 * This method is called when the user clicks the "Remove Item" button
	 * in the remove item batch view.
	 */
	@Override
	public void removeItem() 
        {
            String bCode = getView().getBarcode();
            Item i;
            try{
            	i = model.getItem(bCode);
            }
            catch (Exception e)
            {
            	i = null;
            }
            
            
            if(i == null)
            {
                getView().displayErrorMessage("The specified item does not exisit");
                clearInputBox();
                return;
            }
            
            addToRemovedItemMap(i);
            
            
            try
            {
                model.removeItem(i);
            }
            catch(Exception e)
            {
                e.printStackTrace();
            }
            enableUndoRedo();
            clearInputBox();
            loadValues();
            reloadItems();
	}
	
	/**
	 * This method is called when the user clicks the "Redo" button
	 * in the remove item batch view.
	 */
	@Override
	public void redo() 
	{
		Item i = model.redo();
		ProductContainer pc = model.getRemovedItemPC();
		addToRemovedItemMap(i,pc);
		enableUndoRedo();
		clearInputBox();
        loadValues();
        reloadItems();
	}

	/**
	 * This method is called when the user clicks the "Undo" button
	 * in the remove item batch view.
	 */
	@Override
	public void undo() 
	{
		Item i = model.undo();
		removeFromRemovedItemMap(i);
		enableUndoRedo();
		clearInputBox();
        loadValues();
        reloadItems();
	}

	/**
	 * This method is called when the user clicks the "Done" button
	 * in the remove item batch view.
	 */
	@Override
	public void done() {
		model.clearHistory();
		getView().close();
	}
        
        private void addToRemovedItemMap(Item i)
        {
            Product p = i.getProduct();
            ItemData id = convertToItemData(i);
            
            addToMap(p,id);
            
        }
        private void addToRemovedItemMap(Item i, ProductContainer parent)
        {
            Product p = i.getProduct();
            Item newItem = new Item(p,parent,i.getEntryDate(),(ItemBarcode)i.getBarcode());
            ItemData id = convertToItemData(newItem);
            
            addToMap(p,id);
            
        }
        private void addToMap(Product p, ItemData id)
        {
        	if(removedItems.containsKey(p))
            {
                ArrayList<ItemData> al = removedItems.get(p);
                al.add(id);
            }
            else
            {
                ArrayList<ItemData> al = new ArrayList<ItemData>();
                al.add(id);
                removedItems.put(p, al);
                productsEffected.add(p);
            }
        }
        private void removeFromRemovedItemMap(Item i)
        {
        	Product p = i.getProduct();
        	ItemData id = convertToItemData(i);
        	
        	ArrayList<ItemData> al = removedItems.get(p);
        	al.remove(id);
        	
        	if(al.isEmpty())
        	{
        		productsEffected.remove(p);
        		removedItems.remove(p);
        	}
        }
        
    /*    private ProductData convertToProductData(Product p)
	{
		ProductData newData = new ProductData();
		
		newData.setBarcode(p.getBarcodeString());
		
		newData.setDescription(p.getDescription());
		newData.setShelfLife(String.valueOf( p.getShelfLife() ) );
		newData.setSize(p.getThreeMonthSupply() + "");
		newData.setSupply(String.valueOf( p.getThreeMonthSupply() ) );
                
                int sizeOfProductItems = removedItems.get(p).size();
                newData.setCount(sizeOfProductItems + "");
		
		return newData;
	}*/
        
    /*    private ItemData convertToItemData(Item i)
	{
		ItemData newData = new ItemData();

		newData.setBarcode(i.getBarcodeString());
		newData.setEntryDate(i.getEntryDate().getTime());
		if (i.getExpirationDate() != null)
		{
			newData.setExpirationDate(i.getExpirationDate().getTime());
		}
		else
		{
			newData.setExpirationDate(null);
		}
                
                ContainerType type = i.getProductContainer().getContainerType();
                if(type.equals(ContainerType.STORAGE_UNIT))
                {
                    newData.setStorageUnit(i.getProductContainer().getName());
                    newData.setProductGroup("");
                }
                else
                {
                    newData.setProductGroup(i.getProductContainer().getName());
                    newData.setStorageUnit(
                    model.getParentStorageUnit(i.getProductContainer()).getName());
                }
		return newData;
	}*/
        
        private void clearInputBox()
        {
            getView().setBarcode("");
            getView().enableItemAction(false);
            scannerTimer.stop();
        }

}

